#include "stdafx.h"
#include "ImportProgressDialog.h"
#include "ImportProgressObserverTrampolineWnd.h"

extern HINSTANCE g_hInstance;

LRESULT CImportProgressDialog::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
{
	_pTrampolineWnd = new CImportProgressObserverTrampolineWnd(this);
	_pTrampolineWnd->Create(NULL);
	_pObserver = _pTrampolineWnd;

	_thumbnail.SubclassWindow(GetDlgItem(IDC_THUMBNAIL));

	bHandled = TRUE;

	_hThread = AtlCreateThread(_ImportThread, this);

	GetDlgItem(IDCANCEL).SetFocus();
	return FALSE;	// We've set the focus
}

LRESULT CImportProgressDialog::OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
	CloseHandle(_hThread);
	_pTrampolineWnd->DestroyWindow();
	return 0;
}

LRESULT CImportProgressDialog::OnClickedCancel(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
	EndDialog(wID);
	return 0;
}

void CImportProgressDialog::AddDroppedFile(const CString &strPath)
{
	m_paths.Add(strPath);
}

void CImportProgressDialog::OnSearchStarted()
{
	GetDlgItem(IDC_PROGRESS_CTRL).ModifyStyle(0, PBS_MARQUEE);
	SendDlgItemMessage(IDC_PROGRESS_CTRL, PBM_SETMARQUEE, TRUE, 50);
}

void CImportProgressDialog::OnFoundFile(const CString &strPath)
{
	SetDlgItemText(IDC_PROGRESS_TEXT, strPath);
}

void CImportProgressDialog::OnSearchCompleted()
{
	GetDlgItem(IDC_PROGRESS_CTRL).ModifyStyle(PBS_MARQUEE, 0);
}

void CImportProgressDialog::OnImportStarted()
{
	SendDlgItemMessage(IDC_PROGRESS_CTRL, PBM_SETRANGE32, 0, 100);
}

void CImportProgressDialog::OnDisplayThumbnail(Image *pThumbnail)
{
	_thumbnail.SetThumbnail(pThumbnail);
}

void CImportProgressDialog::OnImportFileStarted(const CString &strFilePath, int num, int denom)
{
	SetDlgItemText(IDC_PROGRESS_TEXT, strFilePath);
	SendDlgItemMessage(IDC_PROGRESS_CTRL, PBM_SETPOS, MulDiv(100, num, denom));
}

void CImportProgressDialog::OnImportCompleted()
{
	CloseHandle(_hThread);
	_hThread = NULL;
}

CString PathStripPath(CString path)
{
	CString result(path);
	PathStripPath(result.GetBuffer(MAX_PATH));
	result.ReleaseBuffer();
	return result;
}

DWORD CImportProgressDialog::ImportThread()
{
	_pObserver->OnSearchStarted();

	CAtlArray<CString> files;
	for (size_t i = 0; i < m_paths.GetCount(); ++i)
	{
		CString strPath = m_paths.GetAt(i);

		_pObserver->OnFoundFile(strPath);

		RecursivelyBuildFileList(strPath, &files);
	}

	_pObserver->OnSearchCompleted();
	_pObserver->OnImportStarted();

	for (size_t i = 0; i < files.GetCount(); ++i)
	{
		CString strFilePath = files.GetAt(i);

		_pObserver->OnImportFileStarted(strFilePath, i + 1, files.GetCount());

		Image *pImage = Image::FromFile(strFilePath);

		Image *pThumbnail = pImage->GetThumbnailImage(0, 0);
		_pObserver->OnDisplayThumbnail(pThumbnail);

#if defined(_DEBUG)
		// TODO: Consider only getting the properties that we support. It might be more efficient to get them individually.
		UINT totalPropertyBufferSize;
		UINT propertyCount;
		pImage->GetPropertySize(&totalPropertyBufferSize, &propertyCount);

		PropertyItem *propertyItems = (PropertyItem *)malloc(totalPropertyBufferSize);
		pImage->GetAllPropertyItems(totalPropertyBufferSize, propertyCount, propertyItems);

		for (UINT propertyIndex = 0; propertyIndex < propertyCount; ++propertyIndex)
		{
			PropertyItem propertyItem = propertyItems[propertyIndex];
			ATLTRACE("id = 0x%04x, length = %d byte(s), type = %d, value @ %p\n",
				propertyItem.id, propertyItem.length, propertyItem.type, propertyItem.value);
		}

		free(propertyItems);
#endif

		UINT propertySize = pImage->GetPropertyItemSize(PropertyTagExifDTOrig);
		PropertyItem *propertyItem = (PropertyItem *)malloc(propertySize);
		if (pImage->GetPropertyItem(PropertyTagExifDTOrig, propertySize, propertyItem) == 0)
		{
			ATLASSERT(propertyItem->type == PropertyTagTypeASCII && propertyItem->length == 20);

			char *q = NULL;
			char *year = strtok_s((char *)propertyItem->value, ":", &q);
			char *month = strtok_s(NULL, ":", &q);
			char *day = strtok_s(NULL, " ", &q);
			
			CString strDestRoot = _T("\\\\SERVER\\Shared\\Photos");
			CString strDestFolder;
			strDestFolder.Format(_T("%hs\\%hs\\%hs"), year, month, day);

			CString strDestFile = PathStripPath(strFilePath);
			CString strDestPath = strDestRoot + _T("\\") + strDestFolder;

			// TODO: Use CreateDirectory instead; SHCreateDirectory is deprecated as of Windows Vista.
			SHCreateDirectory(NULL, strDestPath);

			// TODO: CopyFileEx with progress...
			CString strDestFilePath = strDestPath + _T("\\") + strDestFile;
			CopyFile(strFilePath, strDestFilePath, TRUE);

			// TODO: The option to remove the files from the source...
		}
		free(propertyItem);

		// TODO: std::auto_ptr
		delete pImage;
	}

	_pObserver->OnImportCompleted();
	PostMessage(WM_CLOSE);
	return 0;
}

void CImportProgressDialog::RecursivelyBuildFileList(const CString &strParentPath, CAtlArray<CString> *pFiles)
{
	CString strFileSpec;
	PathCombine(strFileSpec.GetBuffer(MAX_PATH), strParentPath, _T("*.*"));

	WIN32_FIND_DATA find;
	HANDLE hff = FindFirstFile(strFileSpec, &find);
	if (hff != INVALID_HANDLE_VALUE)
	{
		do
		{
			// "." or ".." should not be recursed into.
			if ((_tcscmp(find.cFileName, _T(".")) == 0) || _tcscmp(find.cFileName, _T("..")) == 0)
				continue;

			if (find.dwFileAttributes == INVALID_FILE_ATTRIBUTES)
				continue;

			CString strFullPath;
			PathCombine(strFullPath.GetBuffer(MAX_PATH), strParentPath, find.cFileName);
			strFullPath.ReleaseBuffer();

			if (find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
				RecursivelyBuildFileList(strFullPath, pFiles);
			else
				pFiles->Add(strFullPath);
		} while (FindNextFile(hff, &find));
	}
}
